package gbench.sandbox.data.index;

import static gbench.common.tree.LittleTree.IRecord.REC;
import static gbench.common.tree.LittleTree.Term.FT;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.BiFunction;
import java.util.function.Predicate;

import gbench.common.matlib.algebra.lisp.IRecord;
import gbench.common.matlib.algebra.lisp.MyRecord;
import gbench.commonApp.data.DataApp;

/**
 * 索引引擎
 * 
 * @author Administrator
 *
 */
public class IndexEngine {

    /**
     * 索引引擎
     * 
     * @param tableAlogrithm 表算法
     * @param table          表名
     * @param index_creator  索引创建函数
     */
    public IndexEngine(final TableAlgorithm tableAlogrithm, final String table,
            final BiFunction<Algorithm, IRecord, String[]> index_creator) {
        super();
        this.table = table;
        this.tableAlgorithm = tableAlogrithm;
        this.index_creator = index_creator;
        final var config = IndexEngine.this.tableAlgorithm.getMatrix().getConfig(); // 读取数据库配置
        this.dataApp = new DataApp() {}.reload2(REC(config.toMap())); // // 加载数据库配置
    }

    /**
     * 
     * @return
     */
    public TableAlgorithm getTableAlgorithm() {
        return tableAlgorithm;
    }

    /**
     * 使用keyword在index_name中检索数据，只检索一条数据
     * 
     * @param index_name 索引名
     * @param keyword    关键词
     * @return 关键词检索的索引值
     */
    public IRecord findOne(final String index_name, final Object keyword) {
        final var indexStore = this.indexStore(index_name); // 提取索引库
        final var uuid = indexStore.get(keyword + ""); // 读取索引

        return this.tableAlgorithm.getMatrix().globalGet(uuid);
    }

    /**
     * 索引库
     * 
     * @param index_name 索引名
     * @return 索引库
     */
    public IndexStore indexStore(final String index_name) {
        final var store = indexStores.computeIfAbsent(index_name, k -> new IndexStore(k));
        return store;
    }

    /**
     * 数据索引
     * 
     * @param dataItems 数据字段流
     * @return IndexEngine 对象本身
     */
    public IndexEngine handle(final List<IRecord> dataItems) {
        dataItems.forEach(e -> this.createIndex(e, x -> true)); // forEach
        return this;
    }

    /**
     * 
     * @return
     */
    public String getTable() {
        return table;
    }

    /**
     * 
     * @author Administrator
     *
     */
    public class IndexStore extends HashMap<Object, UUID> {

        /**
         * 
         * @param index_name
         */
        public IndexStore(final String index_name) {
            this.index_name = index_name;
        }

        /**
         * 索引写入
         * 
         * @param keyword 关键词
         * @param uuid    全局id
         * @return IndexStore 本身
         */
        public IndexStore write(final String keyword, final UUID uuid) {
            this.put(keyword, uuid);
            return this;
        }

        /**
         * 索引名库名
         * 
         * @return
         */
        public String getName() {
            return this.index_name;
        }

        /**
         * 从索引文件中 读取 keyword 的索引数据
         * 
         * @param keyword 关键词
         * @return UUID 索引数据
         */
        public UUID get(final String keyword) {
            return this.computeIfAbsent(keyword, k -> {
                final var dataItem = jdbcget(FT("select * from $0 where $1='$2'", getTable(), index_name, keyword));
                return createIndex(dataItem, e -> e != this);
            }); // computeIfAbsent
        }

        private final String index_name;
        private static final long serialVersionUID = 3338478480019069079L;
    }

    /**
     * jdbc 数据读取
     * 
     * @param sql sql 语句
     * @return Irecord 数据
     */
    public IRecord jdbcget(final String sql) {
        System.err.println(sql);
        final var dataItem = dataApp.jdbcApply(j -> j.sql2maybe(sql)).map(e -> e.toMap()).map(MyRecord::REC)
                .orElse(null);
        return dataItem;
    }

    /**
     * 创建索引
     * 
     * @param dataItem     索引项目
     * @param store_filter store->bool,仓库过滤器,在哪些索引库中写入索引, true 写入,false 不写入
     * @return UUID
     */
    public UUID createIndex(final IRecord dataItem, Predicate<IndexStore> store_filter) {
        if (dataItem == null)
            return null;
        
        final var uuid = tableAlgorithm.getMatrix().globalPut(dataItem);
        final var index_names = index_creator.apply(tableAlgorithm.getAlgorithm(), dataItem);

        for (var index_name : index_names) {
            final var _keyword = dataItem.str(index_name);
            if(_keyword==null) continue;
            final var indexStore = indexStore(index_name);
            if (store_filter.test(indexStore)) {
                indexStore.write(_keyword, uuid); // 写入索引
            } // if
        } // for

        return uuid;
    }

    private final String table;
    private TableAlgorithm tableAlgorithm;
    private BiFunction<Algorithm, IRecord, String[]> index_creator;
    private Map<String, IndexStore> indexStores = new HashMap<>();
    private final DataApp dataApp; // 数据应用
}
